package main

import (
    "fmt"
    "unsafe"
)
// 颜色板，将print打印成特殊颜色，方便查看对应的输出结果
const (
    TextBlack = iota + 30
    TextRed
    TextGreen
    TextYellow
    TextBlue
    TextMagenta
    TextCyan
    TextWhite
)

//将说明打印成蓝色，方便查找打印信息
func debug(s string) {
    fmt.Printf("\x1b[0;%dm%s\x1b[0m\n", TextBlue, s)
}

/*nil学习总结
1，nil是一个变量
// nil is a predeclared identifier representing the zero value for a
// pointer, channel, func, interface, map, or slice type.
var nil Type // Type must be a pointer, channel, func, interface, map, or slice type

// Type is here for the purposes of documentation only. It is a stand-in
// for any Go type, but represents the same type for any given function
// invocation.
type Type int

2，nil 适用于 指针，函数，interface，map，slice，channel 这 6 种类型
3，Go 的变量定义由语言层面确保置 0 分配，确保内存块全 0 数据。
4，以上 6 种变量赋值 nil 的行为都是把变量本身置 0 ，仅此而已。
	slice 的 24 字节管理结构，
	map 的  8 字节指针，
	channel 的 8 字节指针，
	interface 的 16 字节，
	8 字节指针和函数指针也是如此；
5，以上 6 种类型和 nil 进行比较判断本质上都是和变量本身做判断，
	slice 是判断管理结构的第一个指针字段，
	map，channel 本身就是指针，
	interface 也是判断管理结构的第一个指针字段，
	指针和函数变量本身就是指针；
6，interface表示可以理解为(type, value), 当(type, value) = (nil,nil)时，才表示这个interface为nil。
 */


//空的自定义结构
type myStruct struct {}

// 返回一个指针
func initPointer() *myStruct {
    var s *myStruct
    return s
}
//有方法的interface
type IF interface {
    F()
}
func (s myStruct) F() {}

//返回一个结构
func InitItfcType() interface{} {
    var s myStruct
    return s
}
//返回一个interface类型
func InitIfaceIF() IF {
    var s myStruct
    return s
}
func InitIfacePointIF() IF {
    var s *myStruct
    return s
}
//slice 结构， 同系统中定义的slice结构
type mySlice struct {
    array unsafe.Pointer
    len   int
    cap   int
}
// interface结构， 简单的理解为type和value, 实际情况比较复杂
type myItf struct {
    t unsafe.Pointer   //type
    v unsafe.Pointer    //value
}

// v是interface，转换为具体类型时，使用v.(type), 例如, v.(int), v.(string)
func seePointer(m map[string]interface{}) {
    for k,v := range m {
        fmt.Printf("%-10s ", k)
        switch k {
        case "slice":// 1， slice与nil的比较本质，是slice结构中的array指针与nil进行比较, 见case pointer
            s := v.([]int)
            p := (* mySlice)(unsafe.Pointer(&s))
            p.len = 1
            p.cap = 2
            // slice与nil的比较本质，是slice结构中的array指针与0进行比较, 见case pointer
            //修改len和cap并不会改变s==nil的判断结果
            fmt.Printf("addr=%p, val={array:%p, len:%d, cap:%d}, s==nil:%t\n",
                s, p.array, len(s), cap(s), s==nil)

            //修改array, 会改变判断结果
            p.array = unsafe.Pointer(uintptr(0x10223445))
            fmt.Printf("\t\t\taddr=%p, val={array:%p, len:%d, cap:%d}, s==nil:%t\n",
                s, p.array, len(s), cap(s), s==nil)
            // 赋值为nil，其实就是将slice的结构体全部写0，array=0,len=0,cap=0
            s = nil
            fmt.Printf("\t\t\taddr=%p, val={array:%p, len:%d, cap:%d}, s==nil:%t\n",
                s, p.array, len(s), cap(s), s==nil)
        case "interface":// 2， interface与nil进行比较的本质，是interface的结构中的第一个指针与nil进行比较,见case pointer
            //itf := v,
            itf := v
            p := (* myItf)(unsafe.Pointer(&itf))
            fmt.Printf("addr=%p, val={type:%p, value:%p} itf==nil:%t\n", p, p.t, p.v, itf == nil)
            p.v = unsafe.Pointer(uintptr(0x10223445))
            fmt.Printf("\t\t\taddr=%p, val={type:%p, value:%p} itf==nil:%t\n", p, p.t, p.v, itf == nil)
            //与nil进行比较的本质，是与interface的结构中的第一个指针进行比较
            p.t = unsafe.Pointer(uintptr(0x10223445))
            fmt.Printf("\t\t\taddr=%p, val={type:%p, value:%p} itf==nil:%t", p, p.t,p.v, itf == nil)


        case "pointer":// 3， 指针与nil进行比较的本质，是指针直接与0进行比较
            p := v.(unsafe.Pointer)
            fmt.Printf("addr=%p, p==nil:%t", p, p == nil)
        case "func":// 4， func与nil进行比较的本质，是func直接与nil进行比较
            f := v.(func())
            fmt.Printf("addr=%p, f==nil:%t", f, f == nil)
        case "channel":// 5， channel本身是一个指针，与nil进行比较的本质，是指针直接与nil进行比较， 见case pointer
            ch := v.(chan interface{})
            fmt.Printf("addr=%p, ch==nil:%t", ch, ch == nil)
        case "map":// 6， map本身是一个指针，与nil进行比较的本质，是指针直接与nil进行比较, 见case pointer
            ma := v.(map[int]interface{})
            fmt.Printf("addr=%p, m==nil:%t", ma, ma == nil)
        default:
            fmt.Printf("addr=%p, v==nil:%t", v, v == nil)
        }
        fmt.Printf("\n")
    }
}

func seeDefault(m map[string]interface{}) {

    fmt.Printf("%-10s %v\n", "Type", "default value")
    for k,v := range m {
        fmt.Printf("%-10s %v\t", k, v)

        switch k {
        case "slice":
            s := v.([]int)  // interface转[]int
            if s == nil {
                fmt.Print("nil")
            }
        case "map":
            mm := v.(map[int]interface{})
            if mm == nil {
                fmt.Print("nil")
            }
        default:
            if v == nil {
                fmt.Print("nil")
            }
        }

        fmt.Print("\n")
    }
}

//默认0值
/*
bool : false
integer: 0
float: 0.0
string: ""
pointer, function, interface, slice, channel, map: nil
*/
func main() {
    //未手动初始化的各种数据类型，记录到map中，在声明变量时会自动设置一个0值
    m := make(map[string]interface{})
    var sliceDef []int
    var pointDef unsafe.Pointer
    var funcDef func()
    var itfDef interface{}
    var chanDef chan interface{}
    var mapDef map[int]interface{}
    var boolDef bool
    var intDef int
    var floatDef float64
    var strDef string

    m["bool"] = boolDef
    m["int"] = intDef
    m["float"] = floatDef
    m["string"] = strDef
    m["slice"] = sliceDef
    m["pointer"] = pointDef
    m["func"] = funcDef
    m["interface"] = itfDef
    m["channel"] = chanDef
    m["map"] = mapDef

    debug("0, Go 的变量定义由语言层面确保置0分配，确保内存块全0数据, 各数据类型的默认值如下：")
    seeDefault(m)

    debug("0.1, 打印初始指针, 查看各类型的初始值与nil的比较原理")
    seePointer(m)

    debug("1 打印nil, 查看nil的值和类型")
    fmt.Printf("%v, %T\n", nil, nil)

    debug("2 nil==nil比较,编译错误")//编译错误
    //if nil == nil {
        //fmt.Println("nil==nil")
    //}

    debug("3 nil作为自定义变量名， 不推荐")
    //var nil int //编译通过，但不建议使用
    //fmt.Println(nil)
    debug("4 不同类型的变量，虽然值为nil，但是不能直接比较")
    //if mapDef == itfDef {fmt.Println("ok")}//编译错误mapDef == itfDef (operator == not defined on map)
    debug("5 同类型的变量，虽然值为nil，但是不能比较")
    //var f1, f2 func()
    //if f1 == f2 {fmt.Println("ok")}//编译错误f1 == f2 (func can only be compared to nil)

    debug("6 自定义结构和nil比较，编译错误")
    /*
    var s myStruct
    if s == nil { //编译错误
        fmt.Println("s == nil")
    }
    */

    debug("7, 函数返回值为指针, 查看是否为nil")
    myPointer := initPointer()
    fmt.Printf("%T, %v, %t\n", myPointer, myPointer, myPointer == nil)

    debug("8, 函数返回interface, 查看是否为nil")
    myItfc := InitItfcType()
    fmt.Printf("%T, %v, %t\n", myItfc, myItfc, myItfc == nil)

    debug("9, 返回方法, 打印，查看是否为nil")
    myIF := InitIfaceIF()
    fmt.Printf("%T, %v, %t\n", myIF, myIF, myIF == nil)

    debug("9.1 返回方法，函数返回值为指针，打印，查看是否为nil")
    myPif := InitIfacePointIF()//类型为*myStruct, 但是值为nil。是一个interface,因此需要类型和值都为nil
    fmt.Printf("%T, %v, %t\n", myPif, myPif, myPif == nil)

    debug("10, interface和nil的比较, 必须值和类型都为nil，才是true")
    type A interface{}
    type B struct{}
    var a *B
    // interface表示可以理解为(type, value), 当(type, value) = (nil,nil)时，则表示interface为nil
    fmt.Printf("a:%T,  (*B)(nil): %T,  A(nil): %T,  A(a):%T,  nil: %T\n",
        a, (*B)(nil), A(nil), A(a), nil) //
    fmt.Println(a == nil)           //true, 非interface类型和nil比较
    fmt.Println(a == (*B)(nil))     //true， 非interface类型和nil比较
    fmt.Println(a == A(nil))        // false, 非interface类型和interface的nil比较

    fmt.Println(A(a) == nil)        // false,A(a) = (*B, nil) != (nil, nil)
    fmt.Println(A(a) == (*B)(nil))  //true, A(a) = (*B, nil) == (*B, nil)
    fmt.Println(A(a) == A(nil))     //false, A(a) = (*B, nil) != (nil, nil)

    debug("11, 有方法的interface和nil比较")


}
